//////////////////////////////////////////////////////////////////////////////////
//	 Copyright 2011 by Yosef Grabivker, ryuho@homenetworksoft.com
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//////////////////////////////////////////////////////////////////////////////////

#include <wx/wx.h>
#include <iterator>
#include <sstream>
#include "utils.h"

using namespace std;

wxString ExtractMACFromString(const wxString& data, char cMACDEL )
{
	wxString strRes;

	int nPosStart(0);

	std::string strTmp = (const char*)data.ToAscii();

	do
	{
		nPosStart = data.find( cMACDEL,++nPosStart );

		if ( wxNOT_FOUND!=nPosStart && nPosStart>=2 )
		{
			const char* szPos = strTmp.c_str();
			szPos+=nPosStart;

			if ( isalnum( *(szPos-2)) &&
				 isalnum( *(szPos-1)) &&
				 isalnum( *(szPos+1)) &&
				 isalnum( *(szPos+2)) &&
				 *(szPos+3)==cMACDEL )
			{
				break;
			}
		}
	}while( wxNOT_FOUND!=nPosStart );

	nPosStart-=2;

	if ( wxNOT_FOUND!=nPosStart && nPosStart>=0 )
	{
		int nPos(nPosStart);
		size_t i;

		for(i=0;i<5;i++)
		{
			nPos = data.find( cMACDEL, nPos+2 );
	
			if ( cMACDEL==nPos )
				break;
		}

		if (5==i) strRes = data.SubString(nPosStart,nPosStart+MAC_ADDR_SIZE-1);

		strRes = strRes.MakeUpper();
		strRes.Trim();

		size_t lMacSz = strRes.size();

		if ( strRes.size()!=MAC_ADDR_SIZE)
			return wxT("");
	}

	return strRes;
}

wxString ExtractIPFromString(const wxString& data)
{
	wxString strRes;

	size_t nPos(0);
	size_t nPosIpStart(0);
	size_t nPosIpEnd(0);

	std::string strTmp = (const char*)data.ToAscii();

	do
	{
		nPos = data.find( '.',++nPos );

		if (std::string::npos == nPos) break;

		const char* szPos = strTmp.c_str();

		int nDotCount(0);

		nPosIpStart = nPos;

		//Move to addr begin
		while( --nPosIpStart && isdigit(szPos[nPosIpStart]) );

		//Move to first digit
		if (nPosIpStart) ++nPosIpStart;

		nPosIpEnd = nPosIpStart;

		for(;nPosIpEnd<data.size();nPosIpEnd++)
		{
			if ( isdigit(szPos[nPosIpEnd]) ) continue;
			if ( szPos[nPosIpEnd]=='.'  ) 
			{
				++nDotCount;
			}
			else
			{
				break;
			}
		}

		if (3==nDotCount)
		{
			strRes = data.SubString(nPosIpStart,nPosIpEnd);
			break;
		}
	}
	while( nPos<data.size() );


	return strRes;
}


bool IsMACEqual(const wxString& strMAC, const wxString& strMAC1)
{
	bool bRes(false);

	if ( strMAC.size()==strMAC1.size() &&
		strMAC.size() == MAC_ADDR_SIZE  )
	{
		bRes = true;

		for(size_t i=0;i<MAC_ADDR_SIZE;i++)
		{
			if (((i+1)%3)==0) continue;

			if ( strMAC[i]!=strMAC1[i])
			{
				bRes = false;
				break;
			}

		}
	}

	return bRes;
}

TEXTLIST StrToList(const wxString& strIN)
{
	wxString str(strIN);
	TEXTLIST lst;

	if ( !str.IsEmpty() )
	{
		str+=wxT("\n");
		stringstream sIn( (const char*)str.ToAscii() );

		char buf[512];

		while ( !sIn.getline(buf, sizeof(buf)).eof() )
		{
			lst.push_back(buf);
		}

		if ( lst.empty() ) lst.push_back( (const char*)str.ToAscii() );

	}

	return lst;
}


//////////////////////////////////////////////////////////////////////////////////////////////////
//CTimeDiff
CTimeDiff::CTimeDiff(const char* szStage):m_szStage(szStage)
{
	#ifdef _WIN32
	m_iStamp = GetTickCount();
	#endif
}

CTimeDiff::~CTimeDiff()
{
	#ifdef _WIN32
	char buf[1024];
	sprintf(buf, "%s, time: %d\n",m_szStage, GetTickCount()-m_iStamp );
	OutputDebugStringA(buf);
	#endif
}

///////////////////////////////////////////////////////////////////////////////////////////////
//Encode
//
// BASE64 encoding table
//
static const unsigned char utf7enb64[] =
{
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
    'w', 'x', 'y', 'z', '0', '1', '2', '3',
    '4', '5', '6', '7', '8', '9', '+', '/'
};

//
// UTF-7 encoding table
//
// 0 - Set D (directly encoded characters)
// 1 - Set O (optional direct characters)
// 2 - whitespace characters (optional)
// 3 - special characters
//
static const unsigned char utf7encode[128] =
{
    3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3,
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
    2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 3,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 1, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3
};

size_t MailEncode(char *buf, const char *psz, size_t n)
{
    size_t len = 0;

    while (*psz && ((!buf) || (len < n)))
    {
        char cc = *psz++;
        if (cc < 0x80 && utf7encode[cc] < 1)
        {
            // plain ASCII char
            if (buf)
                *buf++ = (char)cc;

            len++;
        }
        else
        {
            if (buf)
                *buf++ = '+';

            len++;
            if (cc != '+')
            {
                // BASE64 encode string
                unsigned int lsb, d, l;
                for (d = 0, l = 0; /*nothing*/; psz++)
                {
                    for (lsb = 0; lsb < 2; lsb ++)
                    {
                        d <<= 8;
                        d += lsb ? cc & 0xff : (cc & 0xff00) >> 8;

                        for (l += 8; l >= 6; )
                        {
                            l -= 6;
                            if (buf)
                                *buf++ = utf7enb64[(d >> l) % 64];
                            len++;
                        }
                    }

                    cc = *psz;
                    if (!(cc) || (cc < 0x80 && utf7encode[cc] < 1))
                        break;
                }

                if (l != 0)
                {
                    if (buf)
                        *buf++ = utf7enb64[((d % 16) << (6 - l)) % 64];

                    len++;
                }
            }

            if (buf)
                *buf++ = '-';
            len++;
        }
    }

    if (buf && (len < n))
        *buf = 0;

    return len;
}

std::string MailEncode(const std::string& strSrc)
{
	std::string strRes;

	if ( !strSrc.empty() )
	{
		char* buf = new char[5*strSrc.size()];

		if (buf)
		{
			size_t s = MailEncode(buf, strSrc.c_str(), strSrc.size());

			strRes.assign(buf, s);

			delete [] buf;
		}
	}

	return strRes;
}

/////////////////////////////////////////////////////////////////////////////////
RTSTRING tagMACENTRY::SchedToString() const
{
	RTSTRING strRes;

	std::ostringstream os;
	std::copy(arrSched.begin(), arrSched.end(), 
		std::ostream_iterator<bool>(os, ""));

	strRes =os.str();

	return strRes;
}

void tagMACENTRY::SchedFromString(const RTSTRING& str)
{
	try
	{
		if ( !str.empty() && str.size()==arrSched.size() )
		{
			for(size_t i=0;i<str.size();i++)
			{
				arrSched[i] = str[i]=='1';
			}
		}
	}catch(...)
	{
	}
}

bool tagMACENTRY::IsBlockedByScheduler() const
{
	bool bRes(false);

	if ( bEnableSched )
	{
		wxDateTime tNow(time(NULL));
		unsigned short h = tNow.GetHour();
		unsigned short wd = tNow.GetWeekDay();
		size_t idx = ((size_t)wd)*24+h;

		try
		{
			bRes = !arrSched[idx];
		}
		catch(...)
		{
		}
	}

	return bRes;
}

//! URL encode a string.
wxString URLEncode(const wxString &value)
{
	wxString szToReturn = wxT("");
	unsigned int nPos = 0;

	while( value.length() > nPos ) 
	{
		wxChar cChar = value.GetChar(nPos);

		if( ( isalpha( cChar )) || ( isdigit( cChar )) || (cChar == wxT('-')) || (cChar == wxT('@')) || (cChar == wxT('*')) || (cChar == wxT('_')) )
		{
			szToReturn.Append( cChar );
		}
		else
		{
			switch( cChar )
			{
			//case wxT(' '):  szToReturn.Append(wxT('+')); break;
			case wxT('\n'): szToReturn.Append(wxT("%0D%0A")); break;
			default:
				{
					szToReturn.Append(wxT("%"));
					szToReturn += HexFromInt( cChar );
				}
			}
		}
		nPos++;
	}
	return szToReturn;
}

//! Convert HEX value to an int.  For URL Decoding.
wxString HexFromInt(const int &value)
{
	wxString szHexHolder;

	if( value < 16)
		szHexHolder.Printf(wxT("0%x"), value );
	else
		szHexHolder.Printf(wxT("%x"), value );

	return szHexHolder.MakeUpper();
}

////////////////////////////////////////////////////////////////////////////////////////
void* GetSelectedItemData(wxItemContainer& cont )
{
	void* pRet(NULL);

	int nSel =cont.GetSelection();
	if ( wxNOT_FOUND!=nSel )
	{
		pRet =  cont.GetClientData(nSel);
	}

	return pRet;
}

int GetSelectedItemDataInt( class wxItemContainer& cont )
{
	int nRet(0);

	void* p = GetSelectedItemData(cont);

	nRet = reinterpret_cast<int>(p);

	return nRet;
}